package cn.zlg.common.datadump.condition;

import cn.zlg.common.datadump.enums.QueryConditionConnector;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import lombok.Data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 查询条件组合
 */
@Data
public class QueryFieldConditionSet {
    // 参数名称
   private List<String> names;

   private List<QueryFieldCondition> conditions;
   // 嵌套支持多级条件组合
   private List<QueryFieldConditionSet> conditionSets;

   private QueryConditionConnector connector = QueryConditionConnector.AND;

   public boolean containsName(String name) {
       return names != null && names.contains(name);
   }

   public Predicate buildPredicate(Object value) throws Exception {
       Predicate p = null;
     if(conditions != null && conditions.size() > 0) {
         for(QueryFieldCondition q : conditions) {
             if(connector == QueryConditionConnector.AND) {
                 p = ExpressionUtils.and(p, q.buildPredicate(value));
             } else {
                 p = ExpressionUtils.or(p, q.buildPredicate(value));
             }
         }
     }
     if(conditionSets != null && conditionSets.size() > 0) {
         for(QueryFieldConditionSet q : conditionSets) {
             if(connector == QueryConditionConnector.AND) {
                 p = ExpressionUtils.and(p, q.buildPredicate(value));
             } else {
                 p = ExpressionUtils.or(p, q.buildPredicate(value));
             }
         }
     }
     return p;
   }

   public static Builder Builder() {
       return new Builder();
   }

    public static class Builder {
        private List<String> names = new ArrayList<>(3);

        QueryFieldConditionSet set;

        public Builder names(String... name) {
            if(name != null) {
                List<String> names=            getNames();
                for(String s : name) {
                    if(!names.contains(s)) {
                        names.add(s);
                    }
                }
            }
            return this;
        }

        public Builder and(QueryFieldCondition... conditions) {
            if(conditions==null) {
                return this;
            }
            if(set == null) {
                set = new QueryFieldConditionSet();
                set.conditions = new ArrayList<>(Arrays.asList(conditions));
            } else {
                if (set.connector == QueryConditionConnector.AND) {
                    set.conditions.addAll(Arrays.asList(conditions));
                } else {
                    QueryFieldConditionSet newSet = new QueryFieldConditionSet();
                    newSet.conditionSets = new ArrayList<>(2);
                    newSet.conditionSets.add(set);
                    newSet.conditions = new ArrayList<>(Arrays.asList(conditions));
                    set = newSet;
                }
            }
            return this;
        }

        public Builder or(QueryFieldCondition... conditions) {
            if(conditions==null) {
                return this;
            }
            if(set == null) {
                set = new QueryFieldConditionSet();
                set.conditions = new ArrayList<>(Arrays.asList(conditions));
                set.connector = QueryConditionConnector.OR;
            } else {
                if (set.connector == QueryConditionConnector.OR) {
                    set.conditions.addAll(Arrays.asList(conditions));
                } else {
                    QueryFieldConditionSet newSet = new QueryFieldConditionSet();
                    newSet.connector = QueryConditionConnector.OR;
                    newSet.conditionSets = new ArrayList<>(2);
                    newSet.conditionSets.add(set);
                    newSet.conditions = new ArrayList<>(Arrays.asList(conditions));
                    set = newSet;
                }
            }
            return this;
        }

        public QueryFieldConditionSet build() {
            if(set == null) {
                set = new QueryFieldConditionSet();
            }
            set.setNames(names);
            return set;
        }

        List<String> getNames() {
            if(names == null) {
                names = new ArrayList<>(3);
            }
            return names;
        }
    }
}
